package com.wzh.mall.search.thread;

import org.bouncycastle.asn1.x509.Time;

import java.util.concurrent.*;

/**
 * @program: mall
 * @description: 异步多线程测试类
 * @author: Mr.Wang
 * @create: 2021-09-12 19:44
 **/
public class ThreadTest {
    /*
    * 1、初始化线程的4种方式
    *   1)、继承Thread
    *   2)、实现Runnable接口
    *   3)-实现Callable接口+ FutureTask (可以拿到返回结果,可以处理异常)
    *   4）线程池
    * */
    // 创建线程池
    // 当前系统中线程池只能有一两个，每个异步任务，都提交给线程池去执行就可以了
    public static ExecutorService service = Executors.newFixedThreadPool(10);

    // 线程池可以做到资源控制的效果 达到系统性能的稳定性
    //
    /*
    * 线程池：
    *   1、创建 ExecutorService
    *       1）、Executors ->  Executors.newFixedThreadPool(10);
    *       2）、->new ThreadPoolExecutor()
    *
    * */

    /*
    * 七大参数：
    * public ThreadPoolExecutor(int corePoolSize, 核心线程数 （线程池一创建 就在线程池中等待使用的线程数，相当于最小线程数）
                              int maximumPoolSize, 最大线程数 （线程池中能允许的最多的线程数，可以用来控制并发）
                              long keepAliveTime, 存活时间 非核心空闲线程的等待时间（当前正在运行的线程数量大于最大数量时，非核心空闲线程的等待时间）
                                                        需要释放的线程是指最大的线程数减去核心的线程数的部分 是需要去释放的 这时候就需要去判断存活时间问题
                              TimeUnit unit,  存活时间的单位
                              BlockingQueue<Runnable> workQueue, 阻塞队列 用来保存任务 如果任务有很多 就将多余的任务放在阻塞队列中，只要有空闲的线程，就回去队列中取出新的任务去执行
                              ThreadFactory threadFactory, 线程的创建工厂 一般都是默认的
                              RejectedExecutionHandler handler 如果阻塞队列满了之后，应该怎么办 按照我们指定的拒绝策略进行拒绝
                              )
    *   工作顺序：运行流程：
    *   1、线程池创建,准备好core数量的核心线程,准备接受任务
    *   2、新的任务进来,用core准备好的空闲线程执行。
    *           (1) 、core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
    *           (2) 、阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
    *           (3) 、max都执行好了。Max-core数量空闲的线程会在keepAliveTime指定的时间后自动销毁。最终保持到core大小
    *           (4) 、如果线程数开到了max的数量,还有新任务进来,就会使用reject指定的拒绝策略进行处理
    *   3、所有的线程创建都是由指定的factory创建的。
    *
    *   一个线程池core 7; max 20 , queue: 50, 100并发进来怎么分配的;
    *   7个立即执行，50个进入队列，再开13个进行执行，剩下的30个使用拒绝策略
    *   如果不想抛弃：CallerRunsPolicy
    *   new LinkedBlockingDeque<>(),默认大小是int的最大值
    *   系统默认的几种线程池
    *       Executors.newCachedThreadPool () core是0,所有都可回收
    *       Executors.newFixedThreadPool()固定大小, core=max;都不可回收
    *       Executors.newScheduledThreadPool ()定时任务的线程池
    *       Executors.newSingleThreadExecutor()单线程的线程池,后台从队列里面获取任务,挨个执行
    *   4、开发中为什么使用线程池
    *   （1）、降低资源的消耗
    *           通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
    *   （2）、提高响应速度
    *           因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
    *   （3）、提高线程的可管理性
    *           线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。
    *           无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配
    *    Future可以获取到异步结果
    * */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main方法开始了");
//        Thread01 thread01 = new Thread01();
//        thread01.start();
//        Runable01 runable01 = new Runable01();
////        runable01.run();
//        new Thread(runable01).run();
//        Callable01 callable01 = new Callable01();
//        FutureTask<Integer> future = new FutureTask<>(callable01);
//        new Thread(future).start();
//        Integer integer = future.get();// 等待整个线程执行完成，获取返回结果  阻塞等待
//        System.out.println(integer);
//        System.out.println("当前线程" + Thread.currentThread().getId());
//        int i = 12 / 2;
//        System.out.println("运行结果：" + i);
        // 重点 线程池方式创建线程
        service.execute(new Runable01());
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        System.out.println("main方法结束了");
    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
        }
    }

    public static class Runable01 implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
        }
    }

    public static class Callable01 implements Callable<Integer>{
        @Override
        public Integer call() {
            System.out.println("当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果：" + i);
            return i;
        }
    }
}

